/*
* Copyright (C) 2010-2012 Magnus Skjegstad
* 
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
* 
* The latest version of this library can be downloaded from http://mist-pubsub.googlecode.com
* 
*/
package com.skjegstad.mist2;

import com.skjegstad.mist2.datatypes.NodeIdentifier;
import com.skjegstad.mist2.exceptions.MistException;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Externalizable;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

/**
 *
 * @author magnus
 */
public class MistUtil {
    private static long startupTimestamp;
    private static boolean debug = false;
    static {
        startupTimestamp = System.currentTimeMillis();
    }

    public static long getRuntimeInMs() {
        return System.currentTimeMillis() - startupTimestamp;
    }

    public static DatagramPacket classToDatagram(Externalizable c, InetAddress destinationAddress, int destinationPort) throws MistException {
        // Add new message to out queue
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream out;
        try {
            out = new ObjectOutputStream(bos);
        } catch (IOException e) {
            throw new MistException("Unable to open ObjectOutputStream", e);
        }

        try {
            c.writeExternal(out);
        } catch (IOException e) {
            throw new MistException("Unable to write MIST message to ObjectOutputStream", e);
        }
        try {
            out.close();
        } catch (IOException e) {
            throw new MistException("Unable to close ObjectOutputStream", e);
        }

        byte[] buf = bos.toByteArray();

        return new DatagramPacket(buf, buf.length, destinationAddress, destinationPort);
    }

    public static void datagramToClass(byte[] packet, Externalizable c) throws MistException {
        ObjectInputStream in;
        try {
            in = new ObjectInputStream(new ByteArrayInputStream(packet));
        } catch (IOException ex) {
            throw new MistException("Unable to create object input stream", ex);
        }
        try {
            c.readExternal(in);
        } catch (Exception ex) {
            throw new MistException("Unable to deserialize class", ex);
        }
        try {
            in.close();
        } catch (IOException ex) {
            throw new MistException("Unable to close object input stream", ex);
        }
    }

    public static void debug(NodeIdentifier node, String msg) {
        if (debug)
        System.err.println("debug: (" + node.getNodeIdentifier() + ", " +
                (System.currentTimeMillis() - startupTimestamp) + "): " + msg);
    }

    public static void debug(String msg) {
        if (debug)
        System.err.println("debug: (" +
                (System.currentTimeMillis() - startupTimestamp) + "): " + msg);
    }

    public static void setDebug(boolean enableDebug) {
        debug = enableDebug;
    }

    public static boolean getDebug() {
        return debug;
    }
    
    public static NetworkInterface askUserForNetworkInterface() throws SocketException {
        
        List<NetworkInterface> interfaces = new ArrayList();        
        {
            Enumeration<NetworkInterface> e = NetworkInterface.getNetworkInterfaces();
            while (e.hasMoreElements()) {
                NetworkInterface iface = e.nextElement();
                interfaces.add(iface);                
            }
        }

        if (System.getProperties().getProperty("java.net.preferIPv4Stack") == null) {        
            System.out.println("\nWarning: Java defaults to IPv6 when available, even for IPv4 multicast addresses. To force Sun Java to use IPv4 add the JVM parameter -Djava.net.preferIPv4Stack=true\n");
        } 
                
        NetworkInterface userIf = null;
                
        while (userIf == null) {
            System.out.println("Please select network interface:\n------------------------------------");
            for (int i = 0; i < interfaces.size(); i++) {                       
                NetworkInterface iface = interfaces.get(i);

                String astr = "";
                Enumeration<InetAddress> ads = iface.getInetAddresses();            
                while (ads.hasMoreElements()) {
                    InetAddress a = ads.nextElement();
                    astr = astr + a.getHostAddress() + " ";
                }

                System.out.println("\t["+i+"]\t" + iface.getDisplayName() + "\t" + iface.getName() + " (" + astr.trim() + ")");
            }


            System.out.print("Select interface: ");
            
            BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
            try {
                Integer i = Integer.valueOf(buf.readLine().trim());
                userIf = interfaces.get(i);
            } catch (Exception ex) {
                continue;
            }
        }
        
        if (userIf != null)
            System.out.println("Using interface " + userIf.getName());
        return userIf;
    }
}
